#include <string.h>
#include "queue.h"

#define BUF_LEN_MAX 4294967295   /* 4G - 1 */
#define ELEMENT_LEN_MAX 1048576  /* 1 MB */

#define ELEMENT_TYPE_DATA    1    /*  有效数据 */
#define ELEMENT_TYPE_FILL    2    /*  填充元素 */

struct _queue_element
{
	int element_len; 		/* 元素总长度 */ 
	int element_type;		/* 元素类型   */
	char element_data[];    /* 数据       */
};

typedef struct _queue_element queue_element_t;

static char g_queue_element_buf[sizeof(queue_element_t) + ELEMENT_LEN_MAX];

/**
 * 初始化队列
 *
 *
 * @return  0:成功,
 */
int queue_create(queue_t *p_queue, char *p_buf, const uint32_t buf_len)
{
	if (!p_queue || !p_buf || buf_len <= 0 || buf_len >= BUF_LEN_MAX)
	{
		return -1;
	}

	memset(p_buf, 0, buf_len);

	p_queue->p_queue_buf = p_buf;
	p_queue->queue_buf_len = buf_len;
	p_queue->p_queue_header = (queue_header_t*)p_buf;

	p_queue->p_queue_header->buf_len = buf_len;
	p_queue->p_queue_header->is_full = 0;
	p_queue->p_queue_header->header = sizeof(queue_header_t);
	p_queue->p_queue_header->tail = p_queue->p_queue_header->header;
	
	return 0;
}

/**
 * 打开队列
 *
 *
 * @return  0:成功,
 */
int queue_open(queue_t *p_queue, const char *p_buf)
{
	if (!p_queue || !p_buf)
	{
		return -1;
	}

	p_queue->p_queue_header = (queue_header_t*)p_buf;

	p_queue->p_queue_buf = (char*)p_buf;
	p_queue->queue_buf_len = p_queue->p_queue_header->buf_len;

	return 0;
}

/**
 *
 * @return 0: 成功, -1: 错误, -2: 队列满, -3:要入队的元素p_data_buf太大
 */
int queue_write(queue_t *p_queue, const char *p_data_buf, const int buf_len)
{
	queue_header_t *p_queue_header;
	queue_element_t *p_queue_element;
	int element_len;

	//---------------------------------
	//
	if (!p_queue || !p_data_buf || buf_len <= 0)
	{
		return -1;
	}

	if (buf_len > ELEMENT_LEN_MAX)
	{
		return -3;
	}

	p_queue_header = p_queue->p_queue_header;
	p_queue_element = (queue_element_t*)g_queue_element_buf;
	element_len = sizeof(queue_element_t) + buf_len;
	//memcpy(p_queue_element->element_data, p_data_buf, buf_len);  //is necessary?

	//---------------------------------
	//判断队列是否有空间插入新元素
	if ( p_queue_header->header == p_queue_header->tail && p_queue_header->is_full )
	{
		return -2;
	}

	if ( p_queue_header->tail < p_queue_header->header  )
	{
		//---------------------------------
		// tail  header  (header>tail)
		if ( p_queue_header->header - p_queue_header->tail < element_len)
		{
			//空间不足
			return -2;
		}
	}
	else
	{
		//---------------------------------
		// header tail  (header<=tail)
		if ( (p_queue_header->buf_len - sizeof(queue_element_t) - p_queue_header->tail) < element_len)
		{
			if (p_queue_header->header - sizeof(queue_header_t) < element_len)
			{
				return -2;
			}
			else
			{
				//---------------------------------
				//在当前tail插入一个填充元素
				p_queue_element->element_len = p_queue_header->buf_len - p_queue_header->tail;
				p_queue_element->element_type = ELEMENT_TYPE_FILL;
				memcpy(p_queue->p_queue_buf + p_queue_header->tail, p_queue_element, sizeof(queue_element_t));

				//---------------------------------
				//将tail移动到起始位置
				p_queue_header->tail = sizeof(queue_header_t); 
			}
		}
	}

	//---------------------------------
	// 插入新元素
	p_queue_element->element_len = element_len;
	p_queue_element->element_type = ELEMENT_TYPE_DATA;
	memcpy(p_queue->p_queue_buf + p_queue_header->tail, p_queue_element, sizeof(queue_element_t));
	memcpy(p_queue->p_queue_buf + p_queue_header->tail + sizeof(queue_element_t), p_data_buf, buf_len);

	p_queue_header->tail += element_len;

	if (p_queue_header->tail == p_queue_header->header)
	{
		//---------------------------------
		// 队列满了
		p_queue_header->is_full = 1;
	}

	return 0;
}

/**
 *
 * @return >0:读取的元素数据长度 , -1: 错误, -2: 队列空 , -3: p_data_buf太小
 */
int queue_read(queue_t *p_queue, char *p_data_buf, const int buf_len)
{
	queue_header_t *p_queue_header;
	queue_element_t *p_queue_element;
	int element_len;

	//---------------------------------
	//
	if (!p_queue || !p_data_buf || buf_len <= 0)
	{
		return -1;
	}

	p_queue_header = p_queue->p_queue_header;

	//---------------------------------
	//判断队列是否为空
	if ( p_queue_header->header == p_queue_header->tail && !(p_queue_header->is_full) )
	{
		return -2;
	}

	//---------------------------------
	// 读元素
	p_queue_element = (queue_element_t*)(p_queue->p_queue_buf + p_queue_header->header);

	if (p_queue_element->element_type == ELEMENT_TYPE_FILL)
	{
		//填充元素
		p_queue_header->header = sizeof(queue_header_t);

		if (p_queue_header->header == p_queue_header->tail)
		{
			//队列为空
			return -2;
		}
			
		p_queue_element = (queue_element_t*)(p_queue->p_queue_buf + p_queue_header->header);
	}

	element_len = p_queue_element->element_len;

	if (p_queue_element->element_len - sizeof(queue_element_t) > buf_len)
	{
		//参数缓冲区太小
		return -3;
	}

	memcpy(p_data_buf, p_queue_element->element_data, p_queue_element->element_len - sizeof(queue_element_t));
	p_queue_header->header += element_len;

	if (p_queue_header->is_full)
	{
		//---------------------------------
		// 取走一个元素，队列不再满
		p_queue_header->is_full = 0;
	}

	return (p_queue_element->element_len - sizeof(queue_element_t));
}

int queue_close(queue_t *p_queue)
{
	p_queue->p_queue_buf = NULL;
	p_queue->queue_buf_len = 0;
	p_queue->p_queue_header = NULL;

	return 0;
}

/*
int queue_len(queue_t *p_queue);
*/
